﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;


namespace HEFramework
{
    /// <summary>
    ///
    /// 加密/解密
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-12-19 16:37:15
    /// ----------------------------------------
    /// </summary>
    public class Aes
    {
        /// <summary>
        /// 加密Key
        /// </summary>
        private byte[] aesKeys;

        /// <summary>
        /// 加密IV
        /// </summary>
        private byte[] aesIVs;

        /// <summary>
        /// 复制用
        /// </summary>
        private byte[] copy;

        public Aes(string _key, string _iv)
        {
            string key = _key;
            string iv = _iv;

            byte[] keys = new byte[16];
            byte[] passwords = Encoding.UTF8.GetBytes(key);
            for (int i = 0; i < keys.Length; ++i)
            {
                if (i < passwords.Length)
                {
                    keys[i] = passwords[i];
                }
                else
                {
                    keys[i] = 0;
                }
            }

            // Key 
            aesKeys = keys;


            byte[] ivs = new byte[16];
            byte[] vectors = Encoding.UTF8.GetBytes(iv);
            for (int i = 0; i < ivs.Length; ++i)
            {
                if (i < vectors.Length)
                {
                    ivs[i] = vectors[i];
                }
                else
                {
                    ivs[i] = 0;
                }
            }

            //IV
            aesIVs = ivs;
        }


        /// <summary>
        /// 获取加密Key
        /// </summary>
        /// <returns></returns>
        private byte[] GetKeys()
        {
            copy = new byte[aesKeys.Length];
            Array.Copy(aesKeys, copy, aesKeys.Length);
            return copy;
        }

        /// <summary>
        /// 获取加密IV
        /// </summary>
        /// <returns></returns>
        private byte[] GetIVs()
        {
            copy = new byte[aesIVs.Length];
            Array.Copy(aesIVs, copy, aesIVs.Length);
            return copy;
        }


        /// <summary>
        /// 获得AesManaged对象实例
        /// </summary>
        /// <returns></returns>
        private AesManaged GetAesManaged()
        {
            AesManaged aesManaged = new AesManaged();
            aesManaged.BlockSize = 128;
            aesManaged.KeySize = 128;
            aesManaged.Mode = CipherMode.CBC;
            aesManaged.Padding = PaddingMode.Zeros;
            aesManaged.Key = GetKeys();
            aesManaged.IV = GetIVs();
            return aesManaged;
        }


        /// <summary>
        /// 对字节流加密（同步）
        /// </summary>
        /// <param name="_bytes"></param>
        /// <returns></returns>
        public byte[] EncryptSyn(byte[] _bytes)
        {
            if (_bytes == null)
            {
                Log.Error("Encrypt bytes null");
                return null;
            }

            AesManaged aesManaged = GetAesManaged();

            if (aesManaged == null)
            {
                Log.Error("[AesManaged] is null");
                return null;
            }

            //加密后的文件流
            byte[] encryptedBytes = null;

            //开始加密
            int length = _bytes.Length;

            using (MemoryStream encryptStream = new MemoryStream(length))
            {
                //创建加密器
                using (ICryptoTransform cryptTransform = aesManaged.CreateEncryptor())
                {
                    //创建加密流
                    using (CryptoStream cryptStream = new CryptoStream(encryptStream, cryptTransform, CryptoStreamMode.Write))
                    {
                        cryptStream.Write(_bytes, 0, length);
                        //立刻释放内容到缓存encryptStream当中
                        cryptStream.FlushFinalBlock();
                        encryptedBytes = encryptStream.ToArray();
                    }
                }
            }

            aesManaged.Clear();
            return encryptedBytes;
        }

        /// <summary>
        ///  对字节流加密（异步）
        /// </summary>
        /// <param name="_bytes"></param>
        /// <param name="_cancellationToken"></param>
        /// <param name="_bufferSize"></param>
        /// <returns></returns>
        public async HETask<byte[]> EncryptAsync(byte[] _bytes, HECancellationToken _cancellationToken = null, int _bufferSize = 4096)
        {
            if (_bytes == null)
            {
                Log.Error("Encrypt bytes null");
                return null;
            }

            AesManaged aesManaged = GetAesManaged();

            if (aesManaged == null)
            {
                Log.Error("[AesManaged] is null");
                return null;
            }

            //加密后的文件流
            byte[] encryptedBytes = null;

            //需要加密的流
            using (MemoryStream inputStream = new MemoryStream(_bytes))
            {
                //开始加密
                using (MemoryStream encryptStream = new MemoryStream(_bytes.Length))
                {
                    //创建加密器
                    using (ICryptoTransform cryptTransform = aesManaged.CreateEncryptor())
                    {
                        //创建加密流
                        using (CryptoStream cryptStream = new CryptoStream(encryptStream, cryptTransform, CryptoStreamMode.Write))
                        {
                            Buffer buffer = Buffer.Get(_bufferSize);
                            int length = 0;
                            while ((length = await inputStream.ReadAsync(buffer.Bytes, 0, buffer.Size)) > 0)
                            {
                                if (_cancellationToken.IsCancel())
                                {
                                    return null;
                                }

                                await cryptStream.WriteAsync(buffer.Bytes, 0, length);
                            }

                            //立刻释放内容到缓存encryptStream当中
                            encryptedBytes = encryptStream.ToArray();
                            cryptStream.FlushFinalBlock();
                            aesManaged.Clear();
                            Buffer.Put(buffer);
                        }
                    }
                }
            }

            return encryptedBytes;
        }


        /// <summary>
        /// 字节流解密（同步）
        /// </summary>
        /// <param name="_bytes"></param>
        public byte[] DecryptSyn(byte[] _bytes)
        {
            if (_bytes == null)
            {
                Log.Error("Encrypt bytes null");
                return null;
            }

            AesManaged aesManaged = GetAesManaged();

            if (aesManaged == null)
            {
                Log.Error("[AesManaged] is null");
                return null;
            }

            //解密后的字节流
            byte[] decryptBytes = null;

            int length = (int)_bytes.Length;

            //需要解密的流
            using (MemoryStream inputStream = new MemoryStream(_bytes))
            {
                //创建解析器
                using (ICryptoTransform cryptTransform = aesManaged.CreateDecryptor())
                {
                    //创建解析流
                    using (CryptoStream cryptStream = new CryptoStream(inputStream, cryptTransform, CryptoStreamMode.Read))
                    {
                        decryptBytes = new byte[length];
                        cryptStream.Read(decryptBytes, 0, length);
                    }
                }
            }

            aesManaged.Clear();
            return decryptBytes;
        }

        /// <summary>
        /// 字节流解密（异步）
        /// </summary>
        /// <param name="_bytes"></param>
        /// <param name="_cancellationToken"></param>
        /// <param name="_bufferSize"></param>
        /// <returns></returns>
        public async HETask<byte[]> DecryptAsync(byte[] _bytes, HECancellationToken _cancellationToken = null, int _bufferSize = 4096)
        {
            if (_bytes == null)
            {
                Log.Error("Encrypt bytes null");
                return null;
            }

            AesManaged aesManaged = GetAesManaged();

            if (aesManaged == null)
            {
                Log.Error("[AesManaged] is null");
                return null;
            }

            //解密后的字节流
            byte[] decryptBytes = null;

            using (MemoryStream inputStream = new MemoryStream(_bytes))
            {
                using (MemoryStream decryptedStream = new MemoryStream(_bytes.Length))
                {
                    //创建解析器
                    using (ICryptoTransform cryptTransform = aesManaged.CreateDecryptor())
                    {
                        //创建解析流
                        using (CryptoStream cryptStream = new CryptoStream(inputStream, cryptTransform, CryptoStreamMode.Read))
                        {
                            int length = 0;
                            Buffer buffer = Buffer.Get(_bufferSize);
                            while ((length = await cryptStream.ReadAsync(buffer.Bytes, 0, buffer.Size)) > 0)
                            {
                                if (_cancellationToken.IsCancel())
                                {
                                    return null;
                                }

                                await decryptedStream.WriteAsync(buffer.Bytes, 0, length);
                            }

                            decryptBytes = decryptedStream.ToArray();
                            Buffer.Put(buffer);
                        }
                    }
                }
            }

            aesManaged.Clear();
            return decryptBytes;
        }
    }
}